package keyword_volatile;

/**
 * 在没有volatile机制确保数据可见性,当thread没有让出CPU执行权,对主内存数据不可见,当让出执行权后会读主内存数据
 * https://stackoverflow.com/questions/13376713/why-modifying-a-shared-variable-in-one-threads-affects-the-other-thread-even-wit
 * @author juntao zhang
 */
public class InterruptTest {
  // volatile确保数据可见性
  static class MyVolatileTest {
    private /*volatile*/ boolean loop = true;

    public void test() throws InterruptedException {
      // thread会持续运行
      Thread someThread = new Thread(() -> {
        System.out.println(Thread.currentThread() + " begin");
        int i = 0;
        while (loop) {
          i++;
        }
        System.out.println(Thread.currentThread() + " end, i=" + i);
      });
      someThread.start();
      Thread.sleep(100);
      loop = false;
      System.out.println("set loop=" + loop);
    }

    public static void main(String[] args) throws InterruptedException {
      new MyVolatileTest().test();
    }
  }

  // 我们发现while中替换成sleep之后竟然不需要volatile,Thread.sleep醒来之后直接数据可见
  static  class MyVolatileTest2 {
    private boolean loop = true;
    public void test() throws InterruptedException {
      Thread someThread = new Thread(() -> {
        System.out.println(Thread.currentThread() + " begin");
        while (loop) {
          try {
            Thread.sleep(500);
          } catch (InterruptedException ignore) {
          }
//        Thread.yield(); //同样可以
        }
        System.out.println(Thread.currentThread() + " end");
      });
      someThread.start();
      Thread.sleep(100);
      loop = false;
      System.out.println("set loop=" + loop);
    }
    public static void main(String[] args) throws InterruptedException {
      new MyVolatileTest2().test();
    }
  }


  // 中断代替volatile
  static class InterruptWakeup {
    public void test() throws InterruptedException {
      Thread someThread = new Thread(() -> {
        System.out.println(Thread.currentThread() + " begin");
        int i = 0;
        while (!Thread.interrupted()) {
          i++;
        }
        System.out.println(Thread.currentThread() + " end, i=" + i);
      });
      someThread.start();
      Thread.sleep(100);
      someThread.interrupt();
      System.out.println("set interrupt");
    }
    public static void main(String[] args) throws InterruptedException {
      new InterruptWakeup().test();
    }
  }

  // 中断后保证数据可见性
  static class InterruptTest1{
    private int sharedVariable = 0;

    public void interruptTest() throws InterruptedException {
      Thread someThread = new Thread(() -> {
        try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
          // Is it here guaranteed that changes before interrupt are always visible here?
          System.out.println(sharedVariable);//中断后可以保证数据可见性
        }
      });
      someThread.start();
      Thread.sleep(100);
      sharedVariable = 10;
      someThread.interrupt();
    }

    public static void main(String[] args) throws InterruptedException {
      new InterruptTest1().interruptTest();
    }
  }

  static class SleepVisibleTest {
    private int sharedVariable = 0;

    public void test() throws InterruptedException {
      Thread someThread = new Thread(() -> {
        try {
          Thread.sleep(500);//sleep 结束之后数据可见性
        } catch (InterruptedException e) {
        }
        System.out.println(sharedVariable);
      });
      someThread.start();
      Thread.sleep(100);
      sharedVariable = 10;
    }

    public static void main(String[] args) throws InterruptedException {
      new SleepVisibleTest().test();
    }
  }
}


